Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Markdown: Modify replace_all to avoid infinite loop #1232

Merged
merged 1 commit into from
Apr 25, 2024

Conversation

xiota
Copy link
Contributor

@xiota xiota commented Mar 4, 2023

This PR modifies replace_all to avoid the infinite loop. In each iteration, replace_all searches for needle starting from the beginning of haystack. If replacement contains needle, the result is an infinite loop. To prevent this from happening, replace_all should continue searching for needle from the end of the previous replacement.

Squashed and rebased from #1128. Resolves #936.

Copy link
Member

@b4n b4n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not tested, but it looks good from here.

@xiota
Copy link
Contributor Author

xiota commented Apr 23, 2024

So... waiting until 2025, when Ubuntu 20.04 is EOL, so can use g_string_replace()?

@elextr
Copy link
Member

elextr commented Apr 24, 2024

LGBI but someone needs to test it.

The problem is that the markdown plugin has been in and out of plugins due to its delayed GTK3 port so its not clear how many users there are, and its likely to go away again due to wekkit2gtk-4.1 (see #1295 (comment)) unless somebody makes necessary changes.

@xiota It needs an active maintainer who can then make decisions like when to swap to new functions even if it makes the plugin not build on older systems, but since you have fixed it without that then yeah probably should wait.

@xiota
Copy link
Contributor Author

xiota commented Apr 24, 2024

@elextr In a comment somewhere, you mention you're on an LTS distro without access to webkit2gtk-4.1? So I can look up what libraries you have available, what distro and release is it?

@elextr
Copy link
Member

elextr commented Apr 24, 2024

IIUC any Ubuntu 20.04 LTS or derivative (eg Linux Mint 20) does not have webkit2gtk-4.1.

@xiota
Copy link
Contributor Author

xiota commented Apr 24, 2024

So... checking availability of any library on the oldest Ubuntu LTS release should be sufficient?

For webkit2gtk, there are a couple discontinued functions that probably need to be updated (in the markdown plugin). Ubuntu 20.04 could be supported with conditional compilation, but if there will be no new geany/plugins release before 20.04 is EOL, there wouldn't be much point.

@elextr
Copy link
Member

elextr commented Apr 24, 2024

There were already some mumblings about a point release due to fixes of potential crashes being merged IIUC, and hopefully the next release won't be as far away as 2.0 was from 1.38, but its hard to tell.

Copy link
Member

@b4n b4n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I extracted the old and new code an tested a bit, and that also works great. FWIW, if somebody didn't catch what the issue was (as in fact it's not mentioned anywhere but "infinite loop"): if the replacement contains the search term, it'll be replaced recursively forever (infinite loop + steady memory growth).

FWIW, I tested using this program:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>

#if 0
/* old */
static void
replace_all(GString *haystack,
            const gchar *needle,
            const gchar *replacement)
{
  gchar *ptr;
  gsize needle_len = strlen(needle);

  /* For each occurrence of needle in haystack */
  while ((ptr = strstr(haystack->str, needle)) != NULL) {
    goffset offset = ptr - haystack->str;
    g_string_erase(haystack, offset, needle_len);
    g_string_insert(haystack, offset, replacement);
  }
}
#else
/* new */
static void
replace_all(GString *haystack,
            const gchar *needle,
            const gchar *replacement)
{
  gchar *ptr;
  gsize needle_len = strlen(needle);
  gsize replacement_len = strlen(replacement);
  goffset offset = 0;

  /* For each occurrence of needle in haystack */
  while ((ptr = strstr(haystack->str + offset, needle)) != NULL) {
    offset = ptr - haystack->str;
    g_string_erase(haystack, offset, needle_len);
    g_string_insert(haystack, offset, replacement);
    offset += replacement_len;
  }
}
#endif

int main(void)
{
#define TEST_REPLACE_ALL(hs, s, r, ex)        \
  G_STMT_START {                              \
    GString *haystack_ = g_string_new(hs);    \
    replace_all(haystack_, s, r);             \
    g_assert_cmpstr(haystack_->str, ==, ex);  \
    g_string_free(haystack_, TRUE);           \
  } G_STMT_END

  TEST_REPLACE_ALL("hello", "a", "b", "hello");
  TEST_REPLACE_ALL("hallo", "a", "b", "hbllo");
  TEST_REPLACE_ALL("foobarbaz", "ba", "BA", "fooBArBAz");
  TEST_REPLACE_ALL("ababab", "ba", "BA", "aBABAb");
  TEST_REPLACE_ALL("ababab", "ab", "AB", "ABABAB");
  TEST_REPLACE_ALL("foobarbaz", "o", "oo", "foooobarbaz");

#undef TEST_REPLACE_ALL

  return 0;
}

@b4n b4n added this to the 2.0.1 milestone Apr 25, 2024
@elextr
Copy link
Member

elextr commented Apr 25, 2024

@b4n said:

if the replacement contains the search term, it'll be replaced recursively forever (infinite loop + steady memory growth).

@xiota said:

replace_all searches for needle starting from the beginning of haystack. If replacement contains needle, the result is an infinite loop.

Those seem to say the same to me, and "infinite loop" (at least until it runs out of memory :-) sounds like the issue, sounds like furious agreement :-D

@b4n
Copy link
Member

b4n commented Apr 25, 2024

Oopsie, I didn't check the OP, only the commit message 😕

@b4n b4n merged commit d851fac into geany:master Apr 25, 2024
@xiota xiota deleted the pr-markdown-replace-all branch April 25, 2024 14:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

When the "Markdown" plug-in is enabled, opening a markdown file containing "@@markdown@@" always freezes.
3 participants